home *** CD-ROM | disk | FTP | other *** search
-
- Here is the poor man's version:
-
- procedure keybd_Event; far; external 'USER' index 289;
-
- procedure PostVKey(bVirtKey: byte; Up: Boolean);
- var
- AXReg,BXReg : Word;
- AXHigh, AXLow, BXHigh, BXLow : Byte;
-
- function MakeWord(L,H: Byte): Word;
- begin
- MakeWord := (H shl 8) + L;
- end;
- begin
- AXLow := bVirtKey;
- if up then AXHigh := $80 else AXHigh := $0;
- AXreg := MakeWord(AXLow,AXHigh);
- BXLow := VkKeyScan(bVirtKey);
- BXHigh := 0;
- BXReg := MakeWord(BXLow,BXHigh);
- asm
- mov bx,BXreg;
- mov ax,AXReg;
- end;
- Keybd_Event;
- end;
-
- then to simulate Shift+Ins you need:-
-
- PostVKey(VK_Shift,false);
- PostVKey(VK_Insert,false);
- PostVKey(VK_Insert,True);
- PostVKey(VK_Shift,True);
-
- Here is the Rolls-Royce version:
- Note: This is commercial and copyrighted code. The source code may not be sold for profit
- (unless Steve is doing the selling).
-
- {This unit is to be included in the app that you are running.}
- unit SKeys;
- interface
- type
- { Return values for SendKeys function }
- TSendKeyError = (sk_None, sk_FailSetHook, sk_InvalidToken, sk_UnknownError);
- function SendKeys(S: String): TSendKeyError;
- implementation
- function SendKeys; external 'SendKey' index 2;
- end.
- (********************************************)
- {Here is the DLL that is used.}
- library SendKey;
- uses
- SysUtils, WinTypes, WinProcs, Messages, Classes, KeyDefs;
- type
- { Error codes }
- TSendKeyError = (sk_None, sk_FailSetHook, sk_InvalidToken, sk_UnknownError);
- { exceptions }
- ESendKeyError = class(Exception);
- ESetHookError = class(ESendKeyError);
- EInvalidToken = class(ESendKeyError);
- { a TList descendant that know how to dispose of its contents }
- TMessageList = class(TList)
- public
- destructor Destroy; override;
- end;
- destructor TMessageList.Destroy;
- var
- i: longint;
- begin
- { deallocate all the message records before discarding the list }
- for i := 0 to Count - 1 do
- Dispose(PEventMsg(Items[i]));
- inherited Destroy;
- end;
- var
- { variables global to the DLL }
- MsgCount: word;
- MessageBuffer: TEventMsg;
- HookHandle: hHook;
- Playing: Boolean;
- MessageList: TMessageList;
- AltPressed, ControlPressed, ShiftPressed: Boolean;
- NextSpecialKey: TKeyString;
-
- function MakeWord(L, H: Byte): Word;
- { macro creates a word from low and high bytes }
- inline(
- $5A/ { pop dx }
- $58/ { pop ax }
- $8A/$E2); { mov ah, dl }
-
- procedure StopPlayback;
- { Unhook the hook, and clean up }
- begin
- { if Hook is currently active, then unplug it }
- if Playing then
- UnhookWindowsHookEx(HookHandle);
- MessageList.Free;
- Playing := False;
- end;
-
- function Play(Code: integer; wParam: word; lParam: Longint): Longint; export;
-
- { This is the JournalPlayback callback function. It is called by Windows }
- { when Windows polls for hardware events. The code parameter indicates what }
- { to do. }
- begin
- case Code of
- hc_Skip: begin
- { hc_Skip means to pull the next message out of our list. If we }
- { are at the end of the list, it's okay to unhook the JournalPlayback }
- { hook from here. }
- { increment message counter }
- inc(MsgCount);
- { check to see if all messages have been played }
- if MsgCount >= MessageList.Count then
- StopPlayback
- else
- { copy next message from list into buffer }
- MessageBuffer := TEventMsg(MessageList.Items[MsgCount]^);
- Result := 0;
- end;
- hc_GetNext: begin
- { hc_GetNext means to fill the wParam and lParam with the proper }
- { values so that the message can be played back. DO NOT unhook }
- { hook from within here. Return value indicates how much time until }
- { Windows should playback message. We'll return 0 so that it's }
- { processed right away. }
- { move message in buffer to message queue }
- PEventMsg(lParam)^ := MessageBuffer;
- Result := 0 { process immediately }
- end
- else
- { if Code isn't hc_Skip or hc_GetNext, then call next hook in chain }
- Result := CallNextHookEx(HookHandle, Code, wParam, lParam);
- end;
- end;
- procedure StartPlayback;
- { Initializes globals and sets the hook }
- begin
- { grab first message from list and place in buffer in case we }
- { get a hc_GetNext before and hc_Skip }
- MessageBuffer := TEventMsg(MessageList.Items[0]^);
- { initialize message count and play indicator }
- MsgCount := 0;
- { initialize Alt, Control, and Shift key flags }
- AltPressed := False;
- ControlPressed := False;
- ShiftPressed := False;
- { set the hook! }
- HookHandle := SetWindowsHookEx(wh_JournalPlayback, Play, hInstance, 0);
- if HookHandle = 0 then
- raise ESetHookError.Create('Couldn''t set hook')
- else
- Playing := True;
- end;
- procedure MakeMessage(vKey: byte; M: word);
- { procedure builds a TEventMsg record that emulates a keystroke and }
- { adds it to message list }
- var
- E: PEventMsg;
- begin
- New(E); { allocate a message record }
- with E^ do begin
- Message := M; { set message field }
- { high byte of ParamL is the vk code, low byte is the scan code }
- ParamL := MakeWord(vKey, MapVirtualKey(vKey, 0));
- ParamH := 1; { repeat count is 1 }
- Time := GetTickCount; { set time }
- end;
- MessageList.Add(E);
- end;
- procedure KeyDown(vKey: byte);
- { Generates KeyDownMessage }
- begin
- { don't generate a "sys" key if the control key is pressed (Windows quirk) }
- if (AltPressed and (not ControlPressed) and (vKey in [Ord('A')..Ord('Z')])) or
- (vKey = vk_Menu) then
- MakeMessage(vKey, wm_SysKeyDown)
- else
- MakeMessage(vKey, wm_KeyDown);
- end;
- procedure KeyUp(vKey: byte);
- { Generates KeyUp message }
- begin
- { don't generate a "sys" key if the control key is pressed (Windows quirk) }
- if AltPressed and (not ControlPressed) and (vKey in [Ord('A')..Ord('Z')]) then
- MakeMessage(vKey, wm_SysKeyUp)
- else
- MakeMessage(vKey, wm_KeyUp);
- end;
- procedure SimKeyPresses(VKeyCode: Word);
- { This function simulates keypresses for the given key, taking into }
- { account the current state of Alt, Control, and Shift keys }
- begin
- { press Alt key if flag has been set }
- if AltPressed then
- KeyDown(vk_Menu);
- { press Control key if flag has been set }
- if ControlPressed then
- KeyDown(vk_Control);
- { if shift is pressed, or shifted key and control is not pressed... }
- if (((Hi(VKeyCode) and 1) <> 0) and (not ControlPressed)) or ShiftPressed then
- KeyDown(vk_Shift); { ...press shift }
- KeyDown(Lo(VKeyCode)); { press key down }
- KeyUp(Lo(VKeyCode)); { release key }
- { if shift is pressed, or shifted key and control is not pressed... }
- if (((Hi(VKeyCode) and 1) <> 0) and (not ControlPressed)) or ShiftPressed then
- KeyUp(vk_Shift); { ...release shift }
- { if shift flag is set, reset flag }
- if ShiftPressed then begin
- ShiftPressed := False;
- end;
- { Release Control key if flag has been set, reset flag }
- if ControlPressed then begin
- KeyUp(vk_Control);
- ControlPressed := False;
- end;
- { Release Alt key if flag has been set, reset flag }
- if AltPressed then begin
- KeyUp(vk_Menu);
- AltPressed := False;
- end;
- end;
- procedure ProcessKey(S: String);
- { This function parses each character in the string to create the message list }
- var
- KeyCode: word;
- Key: byte;
- index: integer;
- Token: TKeyString;
- begin
- index := 1;
- repeat
- case S[index] of
- KeyGroupOpen : begin
- { It's the beginning of a special token! }
- Token := '';
- inc(index);
- while S[index] <> KeyGroupClose do begin
- { add to Token until the end token symbol is encountered }
- Token := Token + S[index];
- inc(index);
- { check to make sure the token's not too long }
- if (Length(Token) = 7) and (S[index] <> KeyGroupClose) then
- raise EInvalidToken.Create('No closing brace');
- end;
- { look for token in array, Key parameter will }
- { contain vk code if successful }
- if not FindKeyInArray(Token, Key) then
- raise EInvalidToken.Create('Invalid token');
- { simulate keypress sequence }
- SimKeyPresses(MakeWord(Key, 0));
- end;
- AltKey : begin
- { set Alt flag }
- AltPressed := True;
- end;
- ControlKey : begin
- { set Control flag }
- ControlPressed := True;
- end;
- ShiftKey : begin
- { set Shift flag }
- ShiftPressed := True;
- end;
- else begin
- { A normal character was pressed }
- { convert character into a word where the high byte contains }
- { the shift state and the low byte contains the vk code }
- KeyCode := vkKeyScan(MakeWord(Byte(S[index]), 0));
- { simulate keypress sequence }
- SimKeyPresses(KeyCode);
- end;
- end;
- inc(index);
- until index > Length(S);
- end;
- function SendKeys(S: String): TSendKeyError; export;
- { This is the one entry point. Based on the string passed in the S }
- { parameter, this function creates a list of keyup/keydown messages, }
- { sets a JournalPlayback hook, and replays the keystroke messages. }
- var
- i: byte;
- begin
- try
- Result := sk_None; { assume success }
- MessageList := TMessageList.Create; { create list of messages }
- ProcessKey(S); { create messages from string }
- StartPlayback; { set hook and play back messages }
- except
- { if an exception occurs, return an error code, and clean up }
- on E:ESendKeyError do begin
- MessageList.Free;
- if E is ESetHookError then
- Result := sk_FailSetHook
- else if E is EInvalidToken then
- Result := sk_InvalidToken;
- end
- else
- { Catch-all exception handler ensures than an exception }
- { doesn't walk up into application stack }
- Result := sk_UnknownError;
- end;
- end;
- exports
- SendKeys index 2;
- begin
- end.
-
- (********************************************)
- unit Keydefs;
- interface
- uses WinTypes;
- const
- MaxKeys = 24;
- ControlKey = '^';
- AltKey = '@';
- ShiftKey = '~';
- KeyGroupOpen = '{';
- KeyGroupClose = '}';
- type
- TKeyString = String[7];
- TKeyDef = record
- Key: TKeyString;
- vkCode: Byte;
- end;
- const
- KeyDefArray : array[1..MaxKeys] of TKeyDef = (
- (Key: 'F1'; vkCode: vk_F1),
- (Key: 'F2'; vkCode: vk_F2),
- (Key: 'F3'; vkCode: vk_F3),
- (Key: 'F4'; vkCode: vk_F4),
- (Key: 'F5'; vkCode: vk_F5),
- (Key: 'F6'; vkCode: vk_F6),
- (Key: 'F7'; vkCode: vk_F7),
- (Key: 'F8'; vkCode: vk_F8),
- (Key: 'F9'; vkCode: vk_F9),
- (Key: 'F10'; vkCode: vk_F10),
- (Key: 'F11'; vkCode: vk_F11),
- (Key: 'F12'; vkCode: vk_F12),
- (Key: 'INSERT'; vkCode: vk_Insert),
- (Key: 'DELETE'; vkCode: vk_Delete),
- (Key: 'HOME'; vkCode: vk_Home),
- (Key: 'END'; vkCode: vk_End),
- (Key: 'PGUP'; vkCode: vk_Prior),
- (Key: 'PGDN'; vkCode: vk_Next),
-
- (Key: 'TAB'; vkCode: vk_Tab),
- (Key: 'ENTER'; vkCode: vk_Return),
- (Key: 'BKSP'; vkCode: vk_Back),
- (Key: 'PRTSC'; vkCode: vk_SnapShot),
- (Key: 'SHIFT'; vkCode: vk_Shift),
- (Key: 'ESCAPE'; vkCode: vk_Escape));
-
- function FindKeyInArray(Key: TKeyString; var Code: Byte): Boolean;
- implementation
- uses SysUtils;
- function FindKeyInArray(Key: TKeyString; var Code: Byte): Boolean;
- { function searches array for token passed in Key, and returns the }
- { virtual key code in Code. }
- var
- i: word;
- begin
- Result := False;
- for i := Low(KeyDefArray) to High(KeyDefArray) do
- if UpperCase(Key) = KeyDefArray[i].Key then begin
- Code := KeyDefArray[i].vkCode;
- Result := True;
- Break;
- end;
- end;
- end.